package com.haojiang.mh.widget.chart;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.haojiang.mh.R;
import com.haojiang.mh.service.entity.StartEndStateBean;
import com.haojiang.mh.service.entity.StatusBean;
import com.haojiang.mh.service.entity.TimeValueBean;
import com.haojiang.mh.utils.ImageUtil;
import com.haojiang.mh.utils.MUtil;
import com.haojiang.mh.utils.SizeUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 双层（柱状背景+曲线上层）
 * 当前用在《体征、环境中-->底层柱状图上层曲线图》
 */
public class SignEnvironmentChartView extends View {

    private TextPaint textPaint;
    //坐标刻度、柱状条、线条、遮罩层 画笔
    private Paint coordinatePaint, columnPaint, linePaint, coverPaint;
    private int columnNumber;//时间段数量
    private int startCoordinate = -1, endCoordinate = -1;//开始坐标和结束坐标
    //当前View的宽、高、默认宽、默认高、绘制区域高度、顶部间隔
    private int width, height, defaultWidth, defaultHeight, drawHeight, paddingTop;
    //X轴文字宽度、X轴文字高度、X轴高度、Y轴文字高度、Y轴宽度
    private int xAxisTextWidth, xAxisTextHeight, xAxisHeight, yAxisTextHeight, yAxisWidth;
    //深睡眠、浅睡眠、rem、清醒 柱状颜色
    private int deepColor, lightColor, remColor, awakeColor;
    //通用、遮罩层、遮罩层、遮罩层线条、曲线对应颜色
    private int commonColor, coverColor, coverLineColor, curveColor;
    private int bottomY;//Y坐标起始点位置
    private int curveWidth, coverWidth;//曲线宽度、遮罩层宽度
    private float xItemWidth, yItemHeight;//X轴间隔款、Y轴间隔高度
    //Y轴起始坐标、坐标间隔、除起点外坐标个数、最大值坐标
    private int yStartCoordinate, yInterval, yCoordinateNum, yMaxCoordinate;
    private Path path = new Path();
    private List<PointF> pointList;//曲线数据点
    private int coverBottom, coverTop;//最佳区域底部、顶部
    private int columnRadius; //柱状条顶部弧度半径
    private boolean isCover = true;//是否有最佳遮罩
    private boolean is24HourXAxis = false;//X轴是否为默认24小时(环境报表使用)
    private boolean isLinkTempUnit = false;//是否是华氏度
    private boolean isLinkPhysical = false;//是否体征关联
    private List<StartEndStateBean> sleepList;//背景数据集
    private List<TimeValueBean> beanList;//曲线数据集
    private Bitmap noDataBitmap;

    public SignEnvironmentChartView(Context context) {
        this(context, null);
    }

    public SignEnvironmentChartView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SignEnvironmentChartView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        @SuppressLint("CustomViewStyleable")
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChartModuleAttribute, defStyleAttr, 0);
        yStartCoordinate = a.getInt(R.styleable.ChartModuleAttribute_cm_y_start, 0);
        yInterval = a.getInt(R.styleable.ChartModuleAttribute_cm_y_interval, 10);
        yCoordinateNum = a.getInt(R.styleable.ChartModuleAttribute_cm_y_number, 10);
        coverBottom = a.getInt(R.styleable.ChartModuleAttribute_cm_cover_bottom, yStartCoordinate);
        coverTop = a.getInt(R.styleable.ChartModuleAttribute_cm_cover_top, yStartCoordinate + yInterval);
        isCover = a.getBoolean(R.styleable.ChartModuleAttribute_cm_is_cover, true);
        is24HourXAxis = a.getBoolean(R.styleable.ChartModuleAttribute_cm_is_24_x, false);
        isLinkTempUnit = a.getBoolean(R.styleable.ChartModuleAttribute_cm_link_temp_unit, false);
        isLinkPhysical = a.getBoolean(R.styleable.ChartModuleAttribute_cm_link_physical, false);
        a.recycle();

        initView(context);
    }

    private void initView(Context context) {
        xAxisTextWidth = SizeUtil.dp2px(context, 30);
        xAxisTextHeight = SizeUtil.dp2px(context, 30);
        xAxisHeight = SizeUtil.dp2px(context, 3);
        yAxisTextHeight = SizeUtil.dp2px(context, 25);
        yAxisWidth = SizeUtil.dp2px(context, 30);
        curveWidth = SizeUtil.dp2px(context, 2);
        coverWidth = 2;
        paddingTop = SizeUtil.dp2px(context, 10);
        columnRadius = SizeUtil.dp2px(context, 2);
        drawHeight = SizeUtil.dp2px(getContext(), 130);

        defaultWidth = SizeUtil.dp2px(context, 340);


        noDataBitmap = ImageUtil.getBitmapFromDrawable(context, R.drawable.img_no_chart_data);
        defaultHeight = noDataBitmap.getHeight();
        deepColor = getResources().getColor(R.color.purple_5) & 0x4CFFFFFF;
        lightColor = getResources().getColor(R.color.purple_3) & 0x4CFFFFFF;
        remColor = getResources().getColor(R.color.purple_2) & 0x4CFFFFFF;
        awakeColor = getResources().getColor(R.color.grey_3) & 0x4CFFFFFF;
        commonColor = getResources().getColor(R.color.white) & 0x33FFFFFF;
        coverColor = getResources().getColor(R.color.grey_5) & 0x4CFFFFFF;
        coverLineColor = getResources().getColor(R.color.white) & 0x19FFFFFF;
        curveColor = getResources().getColor(R.color.white);

        textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextAlign(Paint.Align.CENTER);
        textPaint.setTextSize(SizeUtil.sp2px(context, 10));
        textPaint.setColor(commonColor);

        coordinatePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        coordinatePaint.setStyle(Paint.Style.FILL);
        coordinatePaint.setStrokeWidth(3);
        coordinatePaint.setColor(commonColor);

        columnPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        columnPaint.setStyle(Paint.Style.FILL);

        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setStyle(Paint.Style.STROKE);
        CornerPathEffect cornerPathEffect = new CornerPathEffect(50);
        linePaint.setPathEffect(cornerPathEffect);

        if (!isCover) return;
        coverPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        coverPaint.setStyle(Paint.Style.FILL);
        coverPaint.setColor(coverColor);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        if (sleepList == null || (!is24HourXAxis && sleepList.isEmpty())
                || (beanList == null || beanList.isEmpty())
                || (startCoordinate == -1 || endCoordinate == -1)) {
            canvas.drawBitmap(noDataBitmap, (width - noDataBitmap.getWidth()) * 0.5f, 0, linePaint);
            return;
        }

        xItemWidth = (float) (width - yAxisWidth) / columnNumber;
        yItemHeight = (float) drawHeight / yCoordinateNum;
        yMaxCoordinate = yStartCoordinate + yCoordinateNum * yInterval;
        bottomY = height - xAxisTextHeight - xAxisHeight;

        /* 绘制X轴 */
        drawXAxis(canvas);

        /* 绘制背景柱状图 */
        drawBgColumn(canvas);

        /* 绘制最佳值范围遮罩 */
        drawBestCover(canvas);

        /* 绘制Y轴 */
        drawYAxis(canvas);

        /* 绘制曲线 */
        drawCurve(canvas);
    }

    /**
     * 绘制X轴
     */
    private void drawXAxis(Canvas canvas) {
        if (is24HourXAxis) {
            for (int i = 0; i < 25; i++) {//从左至右
                canvas.drawLine(i * xItemWidth, bottomY, i * xItemWidth, bottomY + xAxisHeight, coordinatePaint);
                if (i == 0 || i == 24 || i % 3 != 0) continue;
                canvas.drawText(
                        String.format(Locale.getDefault(), "%02d:00", (i + 18) % 24),
                        xItemWidth * i,
                        SizeUtil.getBaseLine(textPaint, height, xAxisTextHeight),
                        textPaint
                );
            }
            return;
        }
        int interval;
        if (columnNumber <= 6) {
            interval = 1;
        } else if (columnNumber <= 18) {
            interval = 2;
        } else {
            interval = 3;
        }
        if (columnNumber == 1) {//只有一个小时，左右刻度+左右靠边时间点
            canvas.drawLine(0, bottomY, 0, bottomY + xAxisHeight, coordinatePaint);
            canvas.drawLine(width - yAxisWidth, bottomY, width - yAxisWidth, bottomY + xAxisHeight, coordinatePaint);//刻度线
            canvas.drawText(//最左侧刻度
                    String.format(Locale.getDefault(), "%02d:00", startCoordinate % 24),
                    xAxisTextWidth * 0.5f,
                    SizeUtil.getBaseLine(textPaint, height, xAxisTextHeight),
                    textPaint
            );
            canvas.drawText(//最右侧刻度
                    String.format(Locale.getDefault(), "%02d:00", endCoordinate % 24),
                    width - yAxisWidth - xAxisTextWidth * 0.5f,
                    SizeUtil.getBaseLine(textPaint, height, xAxisTextHeight),
                    textPaint
            );
        } else {//绘制所有刻度以及除顶末端的刻度文字
            for (int i = 0; i <= columnNumber; i++) {
                canvas.drawLine(i * xItemWidth, bottomY, i * xItemWidth, bottomY + xAxisHeight, coordinatePaint);
                if (i != 0 && i != columnNumber && i % interval == 0) {
                    canvas.drawText(
                            String.format(Locale.getDefault(), "%02d:00", (startCoordinate + i) % 24),
                            xItemWidth * i,
                            SizeUtil.getBaseLine(textPaint, height, xAxisTextHeight),
                            textPaint
                    );
                }
            }
        }
    }

    /**
     * 绘制最佳值范围遮罩
     */
    private void drawBestCover(Canvas canvas) {
        if (!isCover) return;
        float coverTopPosition = paddingTop + (yMaxCoordinate - coverTop) * drawHeight * 1.0f / (yMaxCoordinate - yStartCoordinate);
        float coverBottomPosition = paddingTop + (yMaxCoordinate - coverBottom) * drawHeight * 1.0f / (yMaxCoordinate - yStartCoordinate);
        canvas.drawRect(0, coverTopPosition, width, coverBottomPosition, coverPaint);
        linePaint.setStrokeWidth(coverWidth);
        linePaint.setColor(coverLineColor);
        canvas.drawLine(0, coverTopPosition, width, coverTopPosition, linePaint);
        canvas.drawLine(0, coverBottomPosition, width, coverBottomPosition, linePaint);
    }

    /**
     * 绘制Y轴
     */
    private void drawYAxis(Canvas canvas) {
        for (int i = 0; i <= yCoordinateNum; i++) {
            float yItemMidPosition = height - xAxisTextHeight - xAxisHeight - yItemHeight * i;
            canvas.drawCircle(//刻度点
                    width - yAxisWidth,
                    yItemMidPosition,
                    5,
                    coordinatePaint
            );
            if (i == 0) continue;
            int value = yStartCoordinate + i * yInterval;
            canvas.drawText(//刻度文本
                    value + "",
                    width - yAxisWidth * 0.5f,
                    SizeUtil.getBaseLine(textPaint, yItemMidPosition + yAxisTextHeight * 0.5f, yAxisTextHeight),
                    textPaint
            );
        }
    }

    /**
     * 绘制背景折线图
     */
    private void drawBgColumn(Canvas canvas) {
        if (sleepList.isEmpty()) return;
        int columnColor = 0, columnHeight = 0;
        for (int i = 0; i < sleepList.size(); i++) {
            StartEndStateBean ssb = sleepList.get(i);
            if (ssb.getStatus() == 4 || ssb.getStatus() == 5) continue;
            switch (ssb.getStatus()) {
                case 0://深睡眠
                    columnColor = deepColor;
                    columnHeight = drawHeight;
                    break;
                case 1://浅睡眠
                    columnColor = lightColor;
                    columnHeight = drawHeight * 3 / 4;
                    break;
                case 2://REM
                    columnColor = remColor;
                    columnHeight = drawHeight * 5 / 12;
                    break;
                case 3://清醒
                    columnColor = awakeColor;
                    columnHeight = drawHeight / 8;
                    break;
            }
            float start = getXCoordinate(ssb.getStart(), false);
            float end = getXCoordinate(ssb.getEnd(), false);
            path.reset();
            if (end - start <= columnRadius * 2) {
                path.moveTo(start, bottomY);
                path.lineTo(start, bottomY - columnHeight);
                path.lineTo(end, bottomY - columnHeight);
                path.lineTo(end, bottomY);
            } else {
                path.moveTo(start, bottomY);
                path.lineTo(start, bottomY - columnHeight + columnRadius);
                path.quadTo(start, bottomY - columnHeight, start + columnRadius, bottomY - columnHeight);
                path.lineTo(end - columnRadius, bottomY - columnHeight);
                path.quadTo(end, bottomY - columnHeight, end, bottomY - columnHeight + columnRadius);
                path.lineTo(end, bottomY);
            }
            columnPaint.setColor(columnColor);
            canvas.drawPath(path, columnPaint);
        }
    }

    /**
     * 绘制平滑曲线
     */
    private void drawCurve(Canvas canvas) {
        if (pointList == null) pointList = new ArrayList<>();
        pointList.clear();
        for (int i = 0; i < beanList.size(); i++) {
            float x = getXCoordinate(beanList.get(i).getTime(), true);
            if (x < 0 || x > (width - yAxisWidth)) continue;
            int value = beanList.get(i).getValue();
            if (value < yStartCoordinate) value = yStartCoordinate;
            if (value > yMaxCoordinate) value = yMaxCoordinate;
            float y = paddingTop + (yMaxCoordinate - value) * drawHeight * 1.0f / (yMaxCoordinate - yStartCoordinate);
            pointList.add(new PointF(x, y));
        }
        if (pointList.isEmpty()) return;
        // 计算平滑路径(贝塞尔曲线)
        path.reset();
        path.moveTo(pointList.get(0).x, pointList.get(0).y);
        /*float lX = 0, lY = 0;
        for (int i = 1; i < pointList.size(); i++) {
            PointF p = pointList.get(i);//当前点
            // 第一个控制点
            PointF p0 = pointList.get(i - 1);// 预测上一个点
            float x1 = p0.x + lX;
            float y1 = p0.y + lY;
            // 第二个控制点
            PointF p1 = pointList.get((i + 1) < pointList.size() ? (i + 1) : i);// 下一个点
            lX = (p1.x - p0.x) *0.5f * SMOOTHNESS;// (lX,lY) 是参考线的斜率
            lY = (p1.y - p0.y) *0.5f * SMOOTHNESS;
            float x2 = p.x - lX;
            float y2 = p.y - lY;
            // 添加line
            if (x2 < x1) {
                KLog.w("fix line");
                x2 = p.x;
            }
            path.cubicTo(x1, y1, x2, y2, p.x, p.y);
//            path.quadTo(p0.x,p0.y,p.x,p.y);
        }*/
        for (int i = 0; i < pointList.size() - 1; i++) {
            PointF p1 = pointList.get(i + 1);
            path.lineTo(p1.x, p1.y);
        }
        linePaint.setStrokeWidth(curveWidth);
        linePaint.setColor(curveColor);
        linePaint.setStrokeCap(Paint.Cap.ROUND);
        linePaint.setStrokeJoin(Paint.Join.ROUND);
        canvas.drawPath(path, linePaint);
    }

    /**
     * 获取时间轴坐标
     *
     * @param timeString 时间点
     * @param isCurve    是否是上层曲线
     * @return 相对x坐标点
     */
    private float getXCoordinate(String timeString, boolean isCurve) {
        int duration = MUtil.INSTANCE.getTimeDuration(startCoordinate, timeString, "HH:mm");
        float x = (float) (duration * (width - yAxisWidth)) / (3600 * columnNumber);
        return (isCurve && isLinkPhysical) ? (x + (xItemWidth * 0.5f)) : x;
    }

    /**
     * 获取X轴坐标个数
     */
    private void getXColumnNumber() {
        if (is24HourXAxis) {
            columnNumber = 24;
            startCoordinate = 18;
            endCoordinate = 18;
            return;
        }
        if (sleepList == null || sleepList.isEmpty()) return;
        String startTime = sleepList.get(0).getStart();
        if (TextUtils.isEmpty(startTime) || !startTime.contains(":")) {
            startCoordinate = -1;
            return;
        } else {
            startCoordinate = MUtil.INSTANCE.getHourAndMinute(startTime, "HH:mm")[0];
        }
        String endTime = sleepList.get(sleepList.size() - 1).getEnd();
        if (TextUtils.isEmpty(endTime) || !endTime.contains(":")) {
            endCoordinate = -1;
            return;
        } else {
            int[] endHM = MUtil.INSTANCE.getHourAndMinute(endTime, "HH:mm");
            endCoordinate = endHM[0] + (endHM[1] != 0 ? 1 : 0);
        }
        if (startCoordinate == endCoordinate) {
            columnNumber = 24;
        } else {
            columnNumber = endCoordinate - startCoordinate;
            if (endCoordinate < startCoordinate) columnNumber += 24;
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(
                getMeasuredLength(widthMeasureSpec, true),
                getMeasuredLength(heightMeasureSpec, false)
        );
    }

    private int getMeasuredLength(int length, boolean isWidth) {
        int specMode = MeasureSpec.getMode(length);
        int specSize = MeasureSpec.getSize(length);
        int size;
        int padding = isWidth ? getPaddingLeft() + getPaddingRight() : getPaddingTop() + getPaddingBottom();
        if (specMode == MeasureSpec.EXACTLY) {
            size = specSize;
        } else if (specMode == MeasureSpec.UNSPECIFIED) {
            size = isWidth ? defaultWidth : defaultHeight;
        } else {
            size = isWidth ? padding + defaultWidth : padding + defaultHeight;
            if (specMode == MeasureSpec.AT_MOST) {
                size = Math.min(size, specSize);
            }
        }
        return size;
    }

    public void setChartDataNew(List<StatusBean> bgData, List<TimeValueBean> curveData) {
        if (sleepList == null) sleepList = new ArrayList<>();
        sleepList.clear();
        if (beanList == null) beanList = new ArrayList<>();
        beanList.clear();

        if (curveData != null && !curveData.isEmpty()) beanList.addAll(curveData);
        if (bgData != null) {
            if (!bgData.isEmpty()) {
                List<StartEndStateBean> tempList = new ArrayList<>();
                for (StatusBean data : bgData) {
                    StartEndStateBean ses = new StartEndStateBean();
                    ses.setStart(MUtil.INSTANCE.getHM(data.getStart()));
                    ses.setEnd(MUtil.INSTANCE.getHM(data.getEnd()));
                    ses.setStatus(data.getStatus());
                    tempList.add(ses);
                }
                sleepList.addAll(tempList);
            }
            getXColumnNumber();
        }

        defaultHeight = paddingTop + drawHeight + xAxisHeight + xAxisTextHeight;
        requestLayout();
    }

    public void setChartData(List<StartEndStateBean> columnData, List<TimeValueBean> curveData) {
        if (sleepList == null) sleepList = new ArrayList<>();
        sleepList.clear();
        if (beanList == null) beanList = new ArrayList<>();
        beanList.clear();
        if (curveData != null && !curveData.isEmpty()) beanList.addAll(curveData);
        if (columnData != null) {
            if (!columnData.isEmpty()) sleepList.addAll(columnData);
            getXColumnNumber();
        }

        defaultHeight = paddingTop + drawHeight + xAxisHeight + xAxisTextHeight;
        requestLayout();
    }


    public void showNoData() {
        if (sleepList == null) sleepList = new ArrayList<>();
        sleepList.clear();
        if (beanList == null) beanList = new ArrayList<>();
        beanList.clear();
        defaultHeight = noDataBitmap.getHeight();
        requestLayout();
    }
}
